home *** CD-ROM | disk | FTP | other *** search
- /* $Id: todo.c,v 1.46 2000/02/10 14:50:11 chrisf Exp $ */
-
- /*
- Hot Date - A DatebookDB displayer for the PalmPilot
- Copyright (C) 1999 Chris Faherty
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
- #include <Pilot.h>
- #include "callback.h"
- #include "hotdateRsc.h"
- #include "hotdate.h"
- #include "datebook.h"
- #include "todo.h"
-
- extern struct sPrefsR *PrefsR;
- extern Boolean PrefsRdirty;
- extern UInt apptTop, apptDays, apptToDoLine;
- extern Word apptToDoCategory;
- extern DateType apptDate;
-
- /*
- * Static function prototypes
- */
- static Int ToDoListCompare(ApptInfoPtr a1, ApptInfoPtr a2, Long extra);
-
- /*
- * This is the same as ApptListCompare() except that I take into account
- * the user preference for sort order. Since this only applies to ToDo
- * entries, I made this a separate function.
- */
- static Int ToDoListCompare(ApptInfoPtr a1, ApptInfoPtr a2, Long extra)
- {
- Int result;
- UInt d1, d2;
- Boolean alwaysbelow=false;
-
- CALLBACK_PROLOGUE
-
- d1 = DateToInt(a1->date);
- d2 = DateToInt(a2->date);
- /*
- * The point here is that we want undated ToDos to always be below the
- * dated ones, regardless of the user selected sort order.
- */
- if (d1 == toDoNoDueDate) {
- d1 = (UInt) 0xFFFFFFFF;
- alwaysbelow = true;
- }
- if (d2 == toDoNoDueDate) {
- d2 = (UInt) 0xFFFFFFFF;
- alwaysbelow = true;
- }
- if (d1 > d2) result = 1; else if (d1 < d2) result = -1; else result = 0;
- if ((PrefsR->ToDoPrefs.sort == '1') && !alwaysbelow) result = -result;
-
- CALLBACK_EPILOGUE
-
- return result;
- }
-
- /*
- * The way I am doing the ToDos is by adding them along with the Datebook
- * appointments. Therefore I call AddAppointmentToList() to add a ToDo entry.
- */
- UInt GetToDo(DmOpenRef dbP, DateType date, Word days, VoidHand apptLists [],
- UInt counts [])
- {
- ApptInfoPtr apptList;
- LineItemPtr LineItem;
- LineItemType tli;
- UInt startDate, endDate;
- DateType tempDate;
- UInt recordNum;
- UInt totalcount=0, currindex=0;
- UInt totalItems;
- UInt origcount;
- UInt i;
- UInt DOW;
- ULong shrunk;
- VoidHand recordH;
- ToDoDBRecordPtr r;
- TimeType notime={-1, -1};
- DateType nodate={-1, -1};
- Word daysm1=days-1;
-
- /*
- * These are used if the item range is specified. The week is assumed
- * to start on Monday. We don't bother to compute these if the pref is
- * set for 'All of them' or 'This month' because we use simpler methods
- * for those.
- */
- tempDate = date;
- switch (PrefsR->ToDoPrefs.range) {
- case '3': /* Tomorrow */
- DateAdjust(&tempDate, 1);
- startDate = DateToInt(tempDate);
- endDate = startDate;
- break;
- case '4': /* This week */
- case '5': /* Next week */
- case '7': /* Next 7 days */
- case '8': /* Next 14 days */
- case '9': /* Next 21 days */
- case ':': /* Next 31 days, sorry about the cheezy colon */
- /* find the previous Monday */
- DOW = DayOfWeek(tempDate.month, tempDate.day, tempDate.year+1904);
- /* Check if we need to adjust to the beginning of a week */
- if ((PrefsR->ToDoPrefs.range == '4') ||
- (PrefsR->ToDoPrefs.range == '5')) {
- if (DOW > 1) {
- DateDaysToDate(DateToDays(tempDate)-(DOW-1), &tempDate);
- } else if (DOW == 0) {
- /*
- * If Sunday we'll go back to the previous Monday
- * as well
- */
- DateDaysToDate(DateToDays(tempDate)-6, &tempDate);
- }
- }
- /* Check if we want next week */
- if (PrefsR->ToDoPrefs.range == '5') DateAdjust(&tempDate, 7);
- startDate = DateToInt(tempDate);
- switch (PrefsR->ToDoPrefs.range) {
- case '8': i = 13; break;
- case '9': i = 20; break;
- case ':': i = 30; break;
- default: i = 6;
- }
- DateAdjust(&tempDate, i);
- endDate = DateToInt(tempDate);
- break;
- default: /* Today & company */
- startDate = DateToInt(tempDate);
- endDate = startDate;
- }
-
- totalItems = DmNumRecordsInCategory(dbP, apptToDoCategory);
-
- /*
- * Keep in mind that AddAppointmentToList() is expecting the list to
- * be locked already if it exists. So we must lock it down. Don't worry
- * about saving the pointer because it does a MemDeref(). In addition,
- * the list was most likely trimmed and needs to be padded to multiples
- * of 10 items. But that's taken care of in the function.
- */
- if (apptLists[daysm1]) {
- MemHandleLock(apptLists[daysm1]);
- /*
- * There are probably some packed LineItemType elements already
- * present since the handle exists. We want to skip over them and
- * add ApptTypeInfo structures, then sort, and then shrink the new
- * elements down to LineItemType as well.
- */
- shrunk = counts[daysm1]*sizeof(LineItemType);
- } else shrunk = 0;
-
- origcount = counts[daysm1]; /* for the sorting at the end */
-
- /*
- * Add a title for the todo listings. This is drawn in the
- * table callback. I always add this title even if there are
- * no records because you need it to switch categories.
- */
- if (AddAppointmentToList(&apptLists[daysm1], shrunk,
- counts[daysm1]-origcount, origcount, notime,
- notime, nodate, 0, 2)) {
- /*
- * apptToDoLine is the line number where the ToDos start. It is
- * linear from the start of the list so we need to add up the previous
- * counts.
- */
- apptToDoLine = 0;
- for (i=0; i < days; i++) apptToDoLine += counts[i];
- counts[daysm1]++;
- totalcount++;
- }
-
- for (recordNum=0; recordNum < totalItems; recordNum++) {
- if ((recordH = DmQueryNextInCategory(dbP, &currindex,
- apptToDoCategory))) {
- r = MemHandleLock(recordH);
- /*
- * Is it dated? Is it already complete?
- *
- * The past due switch is only going to eliminate items that are
- * past due and beyond the item range. So you will always see
- * past due items within your item range, but you will only see
- * the rest if you set the switch. In the case of the "All items"
- * range, you will only see past due items if you set the switch.
- */
- if (
- /* no due date? */
- ((PrefsR->ToDoPrefs.nodate == '0') &&
- (DateToInt(r->dueDate) == toDoNoDueDate)) ||
- /* completed? */
- ((PrefsR->ToDoPrefs.done == '0') &&
- (r->priority & completeFlag)) ||
- /* past due? */
- ((DateToInt(r->dueDate) < startDate) &&
- (PrefsR->ToDoPrefs.pastdue == '0') &&
- !(r->priority & completeFlag) &&
- (PrefsR->ToDoPrefs.range == '1'))
- ) {
- /* don't show */
- } else {
- /*
- * Is it within the proper date range?
- */
- if (
- /* no due date? */
- (DateToInt(r->dueDate) == toDoNoDueDate) ||
- /* include past due items? */
- ((DateToInt(r->dueDate) < startDate) &&
- (PrefsR->ToDoPrefs.pastdue == '1') &&
- !(r->priority & completeFlag)) ||
- /* all of them? */
- ((PrefsR->ToDoPrefs.range == '1') ||
- /* current month? */
- ((PrefsR->ToDoPrefs.range == '6') &&
- (r->dueDate.month == date.month)) ||
- /* otherwise check date range */
- ((DateToInt(r->dueDate) >= startDate) &&
- (DateToInt(r->dueDate) <= endDate)))
- ) {
- /* always put it under the last day; apptLists[daysm1] */
- if (AddAppointmentToList(&apptLists[daysm1], shrunk,
- counts[daysm1]-origcount, origcount, notime, notime,
- r->dueDate, currindex, 1)) {
- counts[daysm1]++;
- totalcount++;
- }
- }
- }
- MemHandleUnlock(recordH);
- currindex++;
- }
- }
-
- /*
- * This was locked inside AddAppointmentToList, and it is also buffered
- * to 10 positions and must be trimmed. Also we want to sort the ToDos
- * in the list.
- */
- if (apptLists[daysm1] && (counts[daysm1] > origcount)) {
- /*
- * Get the pointer again. Yeah I know this sucks having to
- * deref the handle again but I didn't want to have to carry
- * around a pointer.
- */
- MemHandleUnlock(apptLists[daysm1]);
- apptList = MemHandleLock(apptLists[daysm1]);
- apptList = (ApptInfoPtr) (((char *) apptList)+shrunk);
- if ((counts[daysm1]-origcount-1) >= 2) {
- SysInsertionSort(&apptList[1], counts[daysm1]-origcount-1,
- sizeof(ApptInfoType), (_comparF *) ToDoListCompare, 0L);
- }
- /*
- * Shrink the array down to a more compact structure because we
- * don't need many of the structure elements anymore.
- */
- LineItem = (LineItemPtr) apptList;
- for (i=0; i < (counts[daysm1]-origcount); i++) {
- /*
- * Both LineItem & apptList point to the same spot so make
- * sure to use a temporary holding place when copying.
- */
- tli.recordNum = apptList[i].recordNum;
- tli.startTime = notime;
- tli.date = apptList[i].date;
- LineItem[i] = tli;
- }
- MemHandleUnlock(apptLists[daysm1]);
- MemHandleResize(apptLists[daysm1], counts[daysm1]*sizeof(LineItemType));
- }
-
- return totalcount;
- }
-
- void SelectCategoryPopup(DmOpenRef dbP, TablePtr table, Word row)
- {
- Int curSelection;
- Int newSelection;
- ListPtr lst;
- CharPtr name;
- RectangleType r, r2;
- FormPtr frm;
-
- frm = FrmGetActiveForm();
- lst = FrmGetObjectPtr(frm, FrmGetObjectIndex(frm, listID_todocategories));
-
- /* Unhighlight the row in my table. */
- TblUnhighlightSelection(table);
-
- LstSetPosition(lst, 0, 0);
-
- /* Create a list of categories. */
- CategoryCreateList(dbP, lst, apptToDoCategory, true, true, 1, 0, true);
-
- /* Position the list. */
- TblGetItemBounds(table, row, 0, &r);
- FrmGetObjectBounds(frm, FrmGetObjectIndex(frm, listID_todocategories), &r2);
- LstSetPosition(lst, r.topLeft.x+r.extent.x-r2.extent.x, r.topLeft.y);
-
- /* Display the category list. */
- curSelection = LstGetSelection(lst);
- newSelection = LstPopupList(lst);
-
- /* Was a new category selected? */
- if ((newSelection != curSelection) && (newSelection != -1)) {
- if ((name = LstGetSelectionText(lst, newSelection))) {
- apptToDoCategory = CategoryFind(dbP, name);
- /*
- * Copy the category name into my preferences record and mark
- * it dirty.
- */
- MemSet(PrefsR->todocategory,
- sizeof(PrefsR->todocategory), 0);
- MemMove(PrefsR->todocategory, name, StrLen(name));
- /*
- * No immediate need to write, so we just flag it for when the
- * program ends.
- */
- PrefsRdirty = true;
- if (PrefsR->ToDoPrefs.gotop == '1') apptTop = apptToDoLine;
- /*
- * This is a quickie regen of the table data. It only
- * does the ToDo items because that is the only thing
- * that has changed and we want it to work quickly.
- */
- MainFormLoadTable(frm, 3, apptTop, apptDate, apptDays);
- ShowScrollArrows(frm);
- }
- }
-
- CategoryFreeList(dbP, lst, false, false);
- }
-